import { error } from '../../../output.js'
import call_run from './call.js'

const run = async (runtime, ast, node) => {
  if (node.type !== 'VariableDeclaration') return

  for (const declaration of node.declarations) {
    if (declaration.type === 'VariableDeclarator') {
      if (declaration.init.type === 'string' || declaration.init.type === 'int') {
        const scope = runtime.scopes.get(ast.filepath)

        const constant = scope.get('constant')
        const variable = scope.get('variable')

        if (constant.has(declaration.id.name) || variable.has(declaration.id.name)) {
          error(`Variable ${ declaration.id.name } has been declared`)
        }

        if (node.kind === 'const') {
          constant.set(declaration.id.name, declaration.init.value)
        } else {
          variable.set(declaration.id.name, declaration.init.value)
        }
      } else if (declaration.init.type === 'Identifier') {
        const scope = runtime.scopes.get(ast.filepath)

        const constant = scope.get('constant')
        const variable = scope.get('variable')

        if (constant.has(declaration.id.name) || variable.has(declaration.id.name)) {
          error(`Variable ${ declaration.id.name } has been declared`)
        }

        const _run = (value) => {
          if (node.kind === 'const') {
            constant.set(declaration.id.name, value)
          } else {
            variable.set(declaration.id.name, value)
          }
        }

        const getValue = (runtime, name, filepath) => {
          const scope = runtime.scopes.get(ast.filepath)

          const constant = scope.get('constant')
          const variable = scope.get('variable')

          if (constant.has(name)) return constant.get(name)
          if (variable.has(name)) return variable.get(name)

          if (runtime.parent !== null) return getValue(runtime.parent, name, filepath)
          return null
        }

        const value = getValue(runtime, declaration.init.name, ast.filepath)

        if (value !== null) return _run(value)

        error(`Can't find variable: ${ declaration.init.name }`)
      } else if (declaration.init.type === 'CallExpression') {
        const scope = runtime.scopes.get(ast.filepath)

        const constant = scope.get('constant')
        const variable = scope.get('variable')

        if (constant.has(declaration.id.name) || variable.has(declaration.id.name)) {
          error(`Variable ${ declaration.id.name } has been declared`)
        }

        const value = await call_run(runtime, ast, declaration.init)

        if (node.kind === 'const') {
          constant.set(declaration.id.name, value)
        } else {
          variable.set(declaration.id.name, value)
        }
      } else {
        error(`Can't handle type: ${ declaration.init.type }`)
      }
    } else {
      error(`Can't handle type: ${ declaration.type }`)
    }
  }
}

export default run